Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Window is not defined" even when isPlatformBrowser used. #1675

Closed
2 of 6 tasks
jasonburrows opened this issue May 11, 2020 · 55 comments
Closed
2 of 6 tasks

"Window is not defined" even when isPlatformBrowser used. #1675

jasonburrows opened this issue May 11, 2020 · 55 comments

Comments

@jasonburrows
Copy link

jasonburrows commented May 11, 2020

🐞 Bug report

What modules are related to this issue?

  • aspnetcore-engine
  • builders
  • common
  • express-engine
  • hapi-engine
  • module-map-ngfactory-loader

Is this a regression?

Yes the project worked correctly in all circumstances in Angular 8.1.1

Description

Large Angular 8 application with SSR support. Upgraded to Angular 9. All migration scripts related to my project ran and worked correctly with no errors.

Project works fine with ng serve and builds fine when targeting SSR with the command:
NODE_OPTIONS=--max-old-space-size=8192 ng build --source-map --configuration=development && ng run front:server:development.

When I try to run the resulting server (to host with express / express-engine) it gives the "Window not defined" because of a reference in a third party module. All uses of that module are guarded with an 'isPlatformBrowser' check.

🔬 Minimal Reproduction

Seemingly you just have to include any module that references 3rd party modules that try to access 'window'. Note that this did not cause any problem in Angular 8 as long as you guarded against use of those modules with 'isPlatformBrowser' checks.

Now it seems merely having the module referenced is enough.

Set up a vanilla universal app and then add any angular module that references any non-angular JS module that makes a call to window. Note that this will cause the problem even if the angular module is correctly using isPlatformBrowser.

https://github.com/jasonburrows/angularUniversal1675.git

🔥 Exception or Error


> front@2.30.0 servedev:ssr /Users/me/Development/front
> NODE_ENV=dev node dist/server/main

/Users/me/Development/front/dist/server/main.js:200603
}( window, function factory( Outlayer, getSize ) {
   ^

ReferenceError: window is not defined
    at Object../node_modules/masonry-layout/masonry.js (/Users/me/Development/front/dist/server/main.js:200603:4)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Module../node_modules/ngx-masonry/__ivy_ngcc__/fesm2015/ngx-masonry.js (/Users/me/Development/front/dist/server/main.js:225304:72)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object../src/modules/core/core.module.ts (/Users/me/Development/front/dist/server/main.js:286092:23)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object../src/app/app.module.ts (/Users/me/Development/front/dist/server/main.js:276737:23)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object../src/app/app.server.module.ts (/Users/me/Development/front/dist/server/main.js:276890:22)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object../src/main.server.ts (/Users/me/Development/front/dist/server/main.js:277166:27)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object../server.ts (/Users/me/Development/front/dist/server/main.js:276464:23)
    at __webpack_require__ (/Users/me/Development/front/dist/server/main.js:20:30)
    at Object.0 (/Users/me/Development/front/dist/server/main.js:354592:18)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! front@2.30.0 servedev:ssr: `NODE_ENV=dev node dist/server/main`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the front@2.30.0 servedev:ssr script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/me/.npm/_logs/2020-05-11T15_57_49_863Z-debug.log

🌍 Your Environment


  ng:analytics getGlobalAnalytics +0ms
  ng:analytics Client Analytics config found: false +26ms
  ng:analytics Analytics disabled. Ignoring all analytics. +1ms
  ng:analytics getSharedAnalytics +0ms

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 9.1.5
Node: 12.16.2
OS: darwin x64

Angular: 9.1.6
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.5
@angular-devkit/build-angular     0.901.5
@angular-devkit/build-optimizer   0.901.5
@angular-devkit/build-webpack     0.901.5
@angular-devkit/core              9.1.5
@angular-devkit/schematics        9.1.5
@angular/cdk                      9.2.3
@angular/cli                      9.1.5
@angular/material                 9.2.3
@ngtools/webpack                  9.1.5
@nguniversal/builders             9.1.0
@nguniversal/common               9.1.0
@nguniversal/express-engine       9.1.0
@schematics/angular               9.1.5
@schematics/update                0.901.5
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

@jasonburrows
Copy link
Author

OK - further experimentation.

If you have your own module that you are loading into an angular-universal (9) project and that module references a third party angular module, which in turn references a non-angular module that expects browser features, you will get errors about trying to access those features.

Here are two example npm modules that cause this issue:
ngx-masonry (references masonry.js which expects 'window')
ng2-pdf-viewer (references pdfs-dist which expects 'window')

It doesn't matter if you even use the contents of those modules - merely importing them into one of your local modules will cause the server to throw errors as soon as your local module is first encountered server side (even if lazily loaded).

...so isPlatformBrowser can't help.

So what do we do in these situations? I'm only using browser features in the browser but merely including these modules breaks SSR.

@jasonburrows
Copy link
Author

If you use this:

const template = fs.readFileSync(join(DIST_FOLDER, INDEX_HTML)).toString();
const win = domino.createWindow(template);

global['window']= win;
global['document'] = win.document;
global['navigator'] = win.navigator;
global['Event'] = null;

(note, must appear prior to import { AppServerModule } from './src/main.server';).

This will work in some cases but really just kicks the can down the road.

For example, with our above modules that reference external 'browser only' modules, this solution will get past that error for ngx-masonry, but will still fail with ng2-pdf-viewer because it will try to find the requestAnimationFrame on window, which domino does not provide.

I guess you could just mock your way to freedom but I'd hope there's some way we can avoid faults for importing modules where the offending code isn't even executed.

@jasonburrows
Copy link
Author

After speaking with the author of ngx-masonry and taking a look myself, the calls to masonry.js are ALREADY correctly guarded with an isPlatformBrowser check.

So what are we supposed to do in this case? It seems like no matter how you guard against it the error will be thrown for SSR merely by importing the module no matter who's guarding against it.

@CaerusKaru CaerusKaru added the need: investigation Requires some digging to determine if action is needed label Jun 14, 2020
@CaerusKaru
Copy link
Member

I'm inclined to believe one of two things: either it's a change in configuration that @alan-agius4 maybe can speak to, or it's an issue with the Angular CLI since they handle the actual compilation for SSR. I'll leave it to him to follow up.

@Teebo
Copy link

Teebo commented Jul 31, 2020

@CaerusKaru @jasonburrows hey guys, is there an update on this issue? I have been struggling with it for the past few days

@Teebo
Copy link

Teebo commented Jul 31, 2020

@alan-agius4 bro...

@jasonburrows
Copy link
Author

Nope. Essentially it breaks multi platform support in angular and makes using ‘isPlatformBrowser’ a waste of time that accomplished nothing.

I eventually got past it by literally mocking out every single call that anything I use uses (even had to do it for libs used by libs I use).

Amazing waste of time, total hack, and the fact this totally breaking change hasn’t been even really looked at makes my lose confidence in Angular. I won’t be selecting it for future projects.

@Teebo
Copy link

Teebo commented Aug 2, 2020

@jasonburrows yeah it is a big pain, thanks anyway

@Teebo
Copy link

Teebo commented Aug 3, 2020

@jasonburrows hey man would you please give me a hint on how you did the mocking of the window object even for third party libs.
I tried to offset the error by using domino but it seems to be not helping.

@jasonburrows
Copy link
Author

Sure - so since part of the problem is that it triggers the error on module load (rather than on use), just make sure all your modules get loaded - like don’t lazy load or if you do, trigger the load of those modules manually in the browser.

This at least means it isn’t that hard to ensure you get all the problems.

Next, I use Domino to provide implementations where it provides them. Finally, you will get errors about further missing functions (or whatever is missing). Make note of the name and then look up the proper signature. Implement it, add it to the object that needs it (“window” for example).

For functions that return real values, I did my best to return values that wouldn’t cause any problems. On the plus side, it doesn’t seem like these functions actually get executed so I doubt what you return matters (but don’t get me wrong, I’m not really comfortable about this part).

Doing all that I’ve had my application up and running with no issues (from what I can tell).

If you get stuck let me know - I ran into a few gotchas along the way but don’t remember them all here.

It wasn’t actually that time consuming as fortunately there were only a few things that I needed to mock, but I’m still not confident about having to have done it at all.

Good luck - let me know how it goes and I’ll try to help if you run into something.

...I’m on my phone right now but if you need it I can post some code to clear it up when I’m back at a workstation.

@Teebo
Copy link

Teebo commented Aug 4, 2020

@jasonburrows thank you so much.

So maybe you could spot something on my server.ts file regarding the usage of domino.

(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');

const domino = require('domino');

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { existsSync, readFileSync } from 'fs';

const distFolder = join(process.cwd(), 'dist/motif/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index.html';
const template = readFileSync(join(distFolder, indexHtml)).toString();
const window = domino.createWindow(template.toString());

global['window'] = window;
global['document'] = window.document;
global['self'] = window
global['IDBIndex'] = window.IDBIndex
global['document'] = window.document
global['navigator'] = window.navigator
global['getComputedStyle'] = window.getComputedStyle;

import 'zone.js/dist/zone-node';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';


// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser

  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  return server;
}

function run(): void {
  const port = process.env.PORT || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

Despite having the above configuration, I still get the error as below:
Screenshot from 2020-08-04 09-55-35
I think this issue is related to #1678 (comment)
But in my case, it is caused by Editor.js.
I have wrapped Editor.js in a component, and in my case, the error is due to an instance creation of Editor.js and not on the import level.

@Teebo
Copy link

Teebo commented Aug 7, 2020

@jasonburrows what version is your Angular project?

@jasonburrows
Copy link
Author

@Teebo Angular version is 9.1.5. I don't see anything obvious in your server.ts file although I'm using import for domino (I don't use require anywhere in this file in fact) and the only import I have following the domino/ global object mocking is AppServerModule.

I'm not saying any of that should make a difference but they are the only obvious differences I see for what we are doing.

I'm also not doing anything that is the equivalent of your:

(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');

If the error you are getting now is related to instance creation I don't think it is the same problem as, in theory, instance creation can still be guarded with isPlatformBrowser so you should be able to limit that from happening as part of SSR.

That being said I haven't personally encountered any situation where I could import something that requires it be in a browser at all (without my mock hacks).

I may not be fully understanding your situation though - the error you provide is server side - why are you creating an instance of editor.js on the server at all? Have you tried placing all references to it in an isPlatformBrowser check? Are you sure that it isn't actually on import and you just have some lazy loading in place? I'm just brainstorming though - hard to know specifically what's going on for you.

@Teebo
Copy link

Teebo commented Aug 8, 2020

@jasonburrows thanks, I am wrapping the editor.js code within the isPlatformBrowser, thank you for the points you have raised
I will consider those, you have helped me a lot to at least find a way out, I will take it from here, all the best!

@pathrom
Copy link

pathrom commented Aug 10, 2020

@jasonburrows It is definitely a very painful thing not to find a simple solution to something so obvious.
Could you provide an example of your code, (such as wrapping a third-party library in isPlatform, server.ts or other parts of the code) I think it would be of great help.

@Teebo
Copy link

Teebo commented Aug 10, 2020

@danielptlr below is how I did it, albeit it does not work, maybe it might work for you.
Let me know how it goes if you can

import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID } from "@angular/core";

  constructor(
    @Inject(PLATFORM_ID) private platformId: any,
  ) { }
     if (isPlatformBrowser(this.platformId)) {
       const df = new EditorJS({
       holder: "editorMock",
        placeholder: "Start writing your article..."
      });
    }

@pathrom
Copy link

pathrom commented Aug 10, 2020

@Teebo This doesn't work for me either, apparently for now the only way to use incompatible third party libraries is by editing the code from the same library, this is obviously bad practice. Since in future updates we will have problems, but to solve it momentarily it is a good option.
So it would be great if @jasonburrows showed how I solve this by editing the code of those incompatible libraries.
In my case I have error in jspdf and @ zxing / ngx-scanner

@jasonburrows
Copy link
Author

Here's the part of mine that deals with it. In my example I use domino for most of the required functions but requestAnimationFrame was not defined, so I provided a sloppy mock that just returns zero. Since the issue is only on import (for me), it doesn't really matter what I implement it with.

import 'zone.js/dist/zone-node';

import * as fs from 'fs';
import * as domino from 'domino'

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import * as compression from 'compression';
import * as favicon from 'serve-favicon';

import { existsSync } from 'fs';
import * as http from 'http';

import {configuration} from './server/server.config';


const DIST_FOLDER = join(process.cwd(), 'dist/browser');
const INDEX_HTML = existsSync(join(DIST_FOLDER, 'index.original.html')) ? 'index.original.html' : 'index.html';

const template = fs.readFileSync(join(DIST_FOLDER, INDEX_HTML)).toString();
const win = domino.createWindow(template);
win.requestAnimationFrame = function(callback:FrameRequestCallback){ return 0;};
global['window']= win;
global['document'] = win.document;
global['navigator'] = win.navigator;
global['Event'] = null;


import { AppServerModule } from './src/main.server';

This solved the issue. (Nothing after that is any different than any other angular server.ts file).

Since you are saying it is a problem not on import but on instantiation (which I have not seen as part of this bug) - can you confirm this by importing the component causing the problem but not using it? My project would throw those same errors even if I only imported and did not use, so isPlatformBrowser didn't even come into play.

Another test would be to but some console logging in your isPlatformBrowser test to see if it is really being evaluated corrected or not.

I have found that isPlatformBrowser does correctly tell me if I'm in a browser or not, but it is of no use because anything that needs to be in a browser can't even be imported.

@jasonburrows
Copy link
Author

...I'll add to this and say I bet you will experience the problem regardless of if isPlatformBrowser works correctly or not. I suspect that even if you put your EditorJS instantiation in completely unreachable code it would still fail - I know it looks like it is related to instantiation but, in my case at least, it was not and it looked the same as yours in almost everyway (for @Teebo anyway).

@Teebo
Copy link

Teebo commented Aug 11, 2020

@jasonburrows thank you so much, guess what..

I have downgraded my Angular version to 9.1.12 after this the serve.ts started picking up the mocked window as I had code like below.

Downgrade command: ng update @angular/cli@9 @angular/core@9 you may need to force this operation

global['Element'] = {}

This gave a linter error saying;

var global: NodeJS.Global & typeof globalThis

Property 'prototype' is missing in type '{}' but required in type '{ new (): Element; prototype: Element;

This gave me some hope because, before the downgrade, I did not get this linter error on VS code.
After this, the ssr build and serve worked with a few errors specific to my project
I have also the express engine package version as:
"@nguniversal/express-engine": "^8.1.1"

Before the downgrade it was "@nguniversal/express-engine": "^10.0.1"

Additional changes:

Downgraded angular fire to
@angular/fire@6.0.0

So yeah the downgrade saved me

@jasonburrows
Copy link
Author

@Teebo what version were you on before? I’ll have to avoid it!

@Teebo
Copy link

Teebo commented Aug 11, 2020

@jasonburrows I was on ~10.0.5

@coanpape
Copy link

coanpape commented Aug 18, 2020

@Teebo I believe I am working the same issue and working to resolve... Did you basically go through and clean out all angular 10.x and downgrade to the latest 9.x? I see above that you spec'd
"@nguniversal/express-engine": "^8.1.1"
is this a typo? did you mean "^9.1.1"
In hope that I am getting near a solution... with appreciation

@RomainMarecat
Copy link

After an update to Angular 10+

Angular: 10.1.0
... animations, cli, common, compiler, compiler-cli, core
... elements, forms, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker
Ivy Workspace: Yes

Package                                    Version
--------------------------------------------------------------------
@angular-devkit/architect                  0.1001.0
@angular-devkit/build-angular              0.1001.0
@angular-devkit/build-ng-packagr           0.1001.0
@angular-devkit/build-optimizer            0.1001.0
@angular-devkit/build-webpack              0.1001.0
@angular-devkit/core                       10.1.0
@angular-devkit/schematics                 10.1.0
@angular/cdk                               10.2.0
@angular/flex-layout                       10.0.0-beta.32
@angular/material                          10.2.0
@angular/material-moment-adapter           10.2.0
@ngtools/webpack                           10.1.0
@nguniversal/builders                      10.1.0
@nguniversal/common                        10.1.0
@nguniversal/express-engine                10.1.0
@nguniversal/module-map-ngfactory-loader   9.0.0-next.9
@schematics/angular                        10.1.0
@schematics/update                         0.1001.0
ng-packagr                                 10.1.0
rxjs                                       6.5.5
typescript                                 3.9.7
webpack                                    4.44.1

I encountered a regression compared to Angular 9 version
On the main.server.ts side, I had defined window via domino (everything was functional in ng9):

global['window'] = win;
global['document'] = win.document;
global['CSS'] = null;
global['XMLHttpRequest'] = xmlhttprequest.XMLHttpRequest;
global['Prism'] = null;
global['HTMLAnchorElement'] = win.HTMLAnchorElement;
global['navigator'] = win.navigator;
global['requestAnimationFrame'] = requestAnimationFrame as unknown as (callback: FrameRequestCallback) => number;
global['cancelAnimationFrame'] = cancelAnimationFrame;
global['Element'] = win.Element;
global['Event'] = win.Event;
global['KeyboardEvent'] = win.KeyboardEvent;

Since the release in angular version 10.
The same code no longer works. It seems that global ['window'] is no longer recognized in the main.js suite

ReferenceError: window is not defined
because of node_modules / leaflet / dist / leaflet-src.js from ngx-leaflet which does not work in SSR.

I tried to move the redefinition of the global in the server.ts and the main.server.ts but nothing there still makes the same error.

Has there been a change in the consideration of the global between the versions
@nguniversal/common": "^9.1.0 and @nguniversal/express-engine": "^9.1.0 compare to @nguniversal/common": "^10.1.0" and
"@nguniversal/express-engine": "^10.1.0"

It seems that since 10.1.0 all people can't build in SSR anymore because of a potential script with window.

@coanpape
Copy link

coanpape commented Sep 10, 2020 via email

@jasonburrows
Copy link
Author

So hey @alan-agius4 - any updates on this?

Kinda looks like SSR has been effectively broken for two versions of Angular and its even more broken in 10 than in 9.

What's the update? This is a pretty core feature of Angular - how is it not getting any attention?

@julesmercado
Copy link

@jasonburrows Hi can you try resolving it on Zuck.js? How can I shim it like you did? This is driving my crazy really. I have been at it for a whole 3 days already, I have run into multiple errors and this window is the constant thing up my face.

@jasonburrows
Copy link
Author

jasonburrows commented Nov 29, 2020

@julesmercado what errors are you getting? I literally know nothing about Zuck.js but if I see the errors I might be able to help.

@julesmercado
Copy link

julesmercado commented Nov 29, 2020

It has same problem with the window being undefined since Zuck.js is a 3rd party library. I already got it to work by delaying its import inside isPlatformBrowser just like this one (and so I eliminated the need for it to be imported before the constructor).
if( isPlatformBrowser(self._platformId) ){ import( 'zuck.js' ).then( res =>{ Zuck = res; }

I don't know if it is good practice but it has worked for me.

@jasonburrows
Copy link
Author

Did you try the above example where window is shimmed using domino? If so, what was the problem with that? What version of Angular are you on? What are your app.server.module.ts and server.ts files like? What do the shins you’ve tried for Zuck.ts like? Can you share your code?

I don’t know of any specific problem with how you’ve done it but I don’t think it’s the recommended approach.

@ariaschmario
Copy link

Any Updates?

@Jps-Yoda
Copy link

Jps-Yoda commented Sep 7, 2021

I am working with angular 12, and I am still facing this issue with a third library. I tried all the domino solutions but they are not working.

@vitordhers
Copy link

Same here, I'm having the following errors:
TypeError: Cannot redefine property: constructor at
/dist/app/server/vendors~polyfills-dom.js:37:96

@Santoshah
Copy link

Santoshah commented Sep 16, 2021

Angular version 12.0.1 still getting this issue.

image

Followed reference link
Reference lnk 2

(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');


import { join } from 'path';
const domino = require('domino');
const fs = require('fs');
const path = require('path');

const distFolder = join(process.cwd(), 'dist/treo/browser');
const template = fs.readFileSync(path.join(distFolder, 'index.html')).toString();
const win = domino.createWindow(template.toString());
global['window'] = win;
global['document'] = win.document;
global['DOMTokenList'] = win.DOMTokenList;
global['Node'] = win.Node;
global['Text'] = win.Text;
global['HTMLElement'] = win.HTMLElement;
global['navigator'] = win.navigator;

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { APP_BASE_HREF } from '@angular/common';
import 'zone.js/dist/zone-node';
import { AppServerModule } from './src/main.server';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/treo/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  return server;
}

function run(): void {
  const port = process.env.PORT || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

Still issue. Not able to fix.

@Santoshah
Copy link

Santoshah commented Sep 17, 2021

Updating tsconfig.server.json

"module": "commonjs" inside compilerOptions solve the issue for window not defined.

Angular version 12.0.1

{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "./out-tsc/server",
    "target": "es2019",
    "types": [
      "node"
    ]
  },
  "files": [
    "src/main.server.ts",
    "server.ts"
  ],
  "angularCompilerOptions": {
    "entryModule": "./src/app/app.server.module#AppServerModule"
  }
}

Again I am stuck with with svg not defined.

@mocanapena
Copy link

Hello all, any progress on this? Working fine for me in angular versions =< 9, not working for 10+.

Content of my server.ts is similar to the one posted by @Santoshah, which working fine in Angular9 but not for more recent versions. Still having ReferenceError: window is not defined

@Santoshah
Copy link

Hi @mocanapena

You will also need to make reference window object. Here is an example

import { PLATFORM_ID } from "@angular/core";
import { isPlatformBrowser } from '@angular/common';
import { WindowRef } from './services/windowRef.service';
...
constructor(
 @Inject(PLATFORM_ID) private platformId: any,
 private windowRef: WindowRef
){}
...
if(isPlatformBrowser(this.platformId)) {
  // Use the window reference: this.windowRef
 Eg: this.windowRef.nativeWindow.location.pathname
}

credit link

@mocanapena
Copy link

Hello @Santoshah I forgot to mention that it happens only for server-side rendering usecase, when doing serve:ssr. I don't think your fix would solve the issue, as I already tried even when I was pretty sure it wouldn't work.

@Santoshah
Copy link

@mocanapena Let's not assume things on our own.

I had the same issue 10 days back. Whenever I try to run npm run serve:ssr I get windows not defined.

I have also open stack explaing my question here . I fixed them by following this website

and lastly i updated the tsconfig.server.json

"module": "commonjs" inside compilerOptions solve the issue for window not defined.

You need to update every window object to the reference. Also make sure you do no have localstorage used or you need to make a reference to window in that case also.

I have manage to fixed this issue in my Angular 12.0.1 v project. Its very big and it took 3 days to fixed that issue and making changes all over the site. If you need personal assistant I can help. (its FREE). lets connect via skype: cssmaniaa

@mocanapena
Copy link

mocanapena commented Oct 4, 2021

After few days busy I could finally test solution provided by @Santoshah and I can confirm is working fine.
Many thanks for your help and your kindly support :)

@Santoshah
Copy link

@mocanapena Glad to help :)

@lkhatkar
Copy link

Solution provided by @Santoshah still doesn't work on Angular 11.
Still looking for solution.
Many thanks.

@MaxwellADN
Copy link

MaxwellADN commented Oct 22, 2021

Hello
I have the same problem with angular universal.
I have a check with the method isBrowserPlatform in all the places where I called the window but nothing changed. I did the same for the localStorage with the @Santoshah method but nothing to do.
I have a huge project and these changes take me a lot of time
I also tried many other solutions like domino etc...
There is nothing to do
My angular version is 12
Thanks anyway for all yours answers

@ohabash

This comment was marked as spam.

@syahirudean
Copy link

Is there a concrete solution for this yet? I’m stuck. Thanks.

@stephane-tessier
Copy link

Hi

I had the same problem. It was caused by a third party lib that I couldn't modify.
I fixed it by importing that lib only in browser mode:

if (this.winRef.isBrowser()) {
    const lib = require('my-lib'); // eslint-disable-line
    // then do something with the lib
}

make sure add node to the types in tsconfig.app.json so that require is allowed:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": [
      "node"
    ]
  },
  ...
}

Hope it helps.

@BazylPL
Copy link

BazylPL commented Oct 29, 2022

Got the error from tiny-slider lib :( None of the workarounds helped in my case.
Need to abandon SSR for now ;/

@Santoshah
Copy link

Wrap that slider function inside the isBrowser condition. it should work.

import { PLATFORM_ID } from "@angular/core";
import { isPlatformBrowser } from '@angular/common';
constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
) {
    this.isBrowser = isPlatformBrowser(this.platformId);
}

ngOnInit() {

    if (this.isBrowser) {
        run tiny slider.
    }

}

@aleksandraamashukeli
Copy link

hey, maybe someone will find this useful, works for angular 11 (and leaflet)
p.s. thanks @Santoshah i was missing "module": "commonjs" inside compilerOptions
image

@alan-agius4
Copy link
Collaborator

Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on StackOverflow using tag angular-universal.

If you are wondering why we don't resolve support issues via the issue tracker, please check out this explanation.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests